#include <winhack.h>
#include <elasys_server.h>
#include <elasysapi.h>
#include <stdlib.h>
#include "CFileAttr.h"
#include "CBasicFile.h"

static DLinkNode      g_FileAttrList;
RTL_CRITICAL_SECTION  g_FileAttrLock;
RTL_CRITICAL_SECTION  DirLock;

void InitialFileAttriList()
{
    g_FileAttrList.Initialize();
    InitializeCriticalSection(&g_FileAttrLock);
    
    InitializeCriticalSection(&DirLock);
}

ECode GetFileAttr(
      /* in  */wchar_t *pFileName,
      /* in  */IBasicFile* pBasicFile,
      /* out */FileAttr ** ppFileAttr)
{
    FileAttr * p = NULL;

    LockList(g_FileAttrLock);
    ForEachDLinkNode(FileAttr*, p, &g_FileAttrList) {
        if (!wcscmp(p->FileName, pFileName)) {
            if (p->curShareMode == FileShareMode_Deny) {
                UnlockList(g_FileAttrLock);
                return E_FS_FILE_BUSY;
            }
            p->objectCount++;
            if (p->pOwner == NULL)
                p->pOwner = pBasicFile;
            
            UnlockList(g_FileAttrLock);
            *ppFileAttr = p;
            return NOERROR;
        }
    }

    p = new FileAttr;
    if (NULL == p) {
        UnlockList(g_FileAttrLock);
        return E_OUT_OF_MEMORY;
    }

    wcscpy(p->FileName, pFileName);
    p->curShareMode = FileShareMode_Write;
    p->objectCount = 1;
    p->pOwner = pBasicFile;

    g_FileAttrList.InsertNext(p);
    UnlockList(g_FileAttrLock);
    *ppFileAttr = p;
    return NOERROR;
}

void RemoveFromFileAttriList(
        /* in */wchar_t *pFileName)
{
    FileAttr * p = NULL;

    LockList(g_FileAttrLock);
    ForEachDLinkNode(FileAttr*, p, &g_FileAttrList) {
        if (!wcscmp(p->FileName, pFileName)) {
            p->Detach();
            UnlockList(g_FileAttrLock);
            delete p;
            return;
         }
    }
    UnlockList(g_FileAttrLock);
}

void DestroyFileAttriList()
{
    FileAttr * pAttr = NULL;

    while (!g_FileAttrList.IsEmpty()) {
    	  pAttr = (FileAttr*)g_FileAttrList.Next();
    	  pAttr->Detach();
    	  delete pAttr;
    }

    DeleteCriticalSection(&g_FileAttrLock);
    DeleteCriticalSection(&DirLock);
}


ECode SetFileShareMode(
      /* in */  IBasicFile * pBasicFile,
      /* in */  FileAttr * pFileAttr,
      /* in */  FileShareMode mode)
{
    ECode ec = NOERROR;
    FileShareMode FMode;
    LockList(g_FileAttrLock);
    if (pFileAttr->objectCount > 1) {
        if (FileShareMode_Deny == pFileAttr->curShareMode
            && pBasicFile != pFileAttr->pOwner) {
            ec = E_FS_FILE_BUSY;
            goto exit1;
        }

        if (FileShareMode_Read == pFileAttr->curShareMode
            && pBasicFile != pFileAttr->pOwner) {
            ec = E_FS_FILE_BUSY;
            goto exit1;
        }
        
        pBasicFile->GetAccessMode(&FMode);
        if ((FMode == FileAccessMode_Read)
            && FileShareMode_Deny == mode) {
            ec = E_FS_FILE_BUSY;
            goto exit1;
        }

        if (FileShareMode_Read == mode
            && FileShareMode_Write == pFileAttr->curShareMode) {
                ec = E_FS_FILE_BUSY;
                goto exit1;
        }
    }

    pFileAttr->curShareMode = mode;
    pFileAttr->pOwner = pBasicFile;

exit1:
    UnlockList(g_FileAttrLock);
    return ec;
}
